/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    bits.h
 *  @brief   Bit operation header file
 *  @version v1.0
 *  @date    03. Apr. 2023
 *  @author  gonght
 ****************************************************************/
#ifndef __BITS_H__
#define __BITS_H__

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#define BITS_PER_LONG           (32UL)
#define BITS_PER_LONG_LONG      (64UL)
#define DIV_ROUND_UP(n,d)       (((n) + (d) - 1) / (d))

#define BIT(nr)                 (1UL << (nr))
#define BIT_ULL(nr)             (1ULL << (nr))
#define BIT_MASK(nr)            (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr)            ((nr) / BITS_PER_LONG)
#define BIT_ULL_MASK(nr)        (1ULL << ((nr) % BITS_PER_LONG_LONG))
#define BIT_ULL_WORD(nr)        ((nr) / BITS_PER_LONG_LONG)
#define BITS_PER_BYTE           8
#define BITS_TO_LONGS(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))

/*
 * Create a contiguous bitmask starting at bit position @l and ending at
 * position @h. For example
 * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
 */
#define GENMASK(h, l) \
	(((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))

#define GENMASK_ULL(h, l) \
	(((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))

#define GET_REG_BITS(var, pos, len)             ({                  \
	typeof(pos) _pos = (pos);                                   \
	typeof(len) _len = (len);                                   \
	((var) & GENMASK(_pos + _len - 1, _pos)) >> (_pos);         \
})

#define SET_REG_BITS(var, pos, len, val)        ({                  \
	typeof(var) _var = (var);                                   \
	typeof(pos) _pos = (pos);                                   \
	typeof(len) _len = (len);                                   \
	typeof(val) _val = (val);                                   \
	_val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos);     \
	_var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val;     \
})

#define __bf_shf(x) (__builtin_ffsll(x) - 1)

/**
 * FIELD_PREP() - prepare a bitfield element
 * @_mask: shifted mask defining the field's length and position
 * @_val:  value to put in the field
 *
 * FIELD_PREP() masks and shifts up the value.  The result should
 * be combined with other fields of the bitfield using logical OR.
 */
#define FIELD_PREP(_mask, _val)                                     \
	({                                                          \
	((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask);       \
	})

/**
* FIELD_GET() - extract a bitfield element
* @_mask: shifted mask defining the field's length and position
* @_reg:  32bit value of entire bitfield
*
* FIELD_GET() extracts the field specified by @_mask from the
* bitfield passed in as @_reg by masking and shifting it down.
*/
#define FIELD_GET(_mask, _reg)                                      \
	({                                                          \
	(typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask));     \
	})

/**
 * FIELD_FIT() - check if value fits in the field
 * @_mask: shifted mask defining the field's length and position
 * @_val:  value to test against the field
 *
 * Return: true if @_val can fit inside @_mask, false if @_val is too big.
 */
#define FIELD_FIT(_mask, _val)                                      \
	({                                                          \
	!((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask));   \
	})

static inline uint32_t ror32(uint32_t word, uint32_t shift)
{
	return (word >> (shift & 31)) | (word << ((-shift) & 31));
}

static inline uint32_t rol32(uint32_t word, uint32_t shift)
{
	return (word << (shift & 31)) | (word >> ((-shift) & 31));
}

#ifdef __cplusplus
}
#endif

#endif /* __BITS_H__ */
